import { Scene } from '@babylonjs/core/scene';
import { AbstractControl, IAbstractControlOptions } from './abstract-control';
import { Control } from '@babylonjs/gui/2D/controls/control';
import { StackPanel } from '@babylonjs/gui/2D/controls/stackPanel';
import { CreateHandleTo, IHandle, RemoveHandle } from '../../data/data-handle';
import { RadioButton } from '@babylonjs/gui/2D/controls/radioButton';
import { TextBlock } from '@babylonjs/gui/2D/controls/textBlock';


/**
 * 单选按钮控件
 * @param group 所在组键名
 * @param title 页眉（标题）
 * @param debug 是否调试绘制（仅开发中使用）
 * @param isVertical 是否纵向布局
 * @param radioSize 单选按钮大小
 * @param fontSize 文字字体大小
 * @param fontFamily 文字字体
 * @param fontColor 文字颜色
 * @param radioBackground 单选按钮背景颜色
 * @param radioColor 单选按钮颜色
 * @param checkSizeRatio 选中标识大小
 * @param spacing 标题与按钮的间隔留白
 * @param revocable 是否可撤销
 * @param fontWeight 字体权重
 */
interface IUIRadioOptions extends IAbstractControlOptions {
    group?: string,
    title?: string,
    debug?: boolean,
    isVertical?: boolean,
    radioSize?: number,
    fontSize?: number,
    fontFamily?: string,
    fontColor?: string,
    radioBackground?: string,
    radioColor?: string,
    checkSizeRatio?: number,
    spacing?: number,
    revocable?: boolean,
    fontWeight?: string,
}


/**
 * 单选按钮组件
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 */
class UIRadio extends AbstractControl {

    private _changeHandles: Array<IHandle<boolean>> = [];
    private _isChecked!: boolean;
    private _radioBackgroundColor!: string;
    private _radioColor!: string;
    private _fontColor!: string;
    private _revocable!: boolean;

    /**
     * 原始单选按钮控件
     */
    public radio!: RadioButton;

    /**
     * 原始标题文字控件
     */
    public header!: TextBlock;

    constructor(name: string, scene: Scene, options?: IUIRadioOptions) {
        super(name, scene, options);
        this.radio.onPointerDownObservable.add(this.breakCamera);
        this.header.onPointerDownObservable.add(this.breakCamera);
    }

    public set isEnabled(enabled: boolean) {
        this.radio.isEnabled = enabled;
        if (this.enabledStyle) this.enabledStyle(enabled, this);
    }
    public get isEnabled(): boolean {
        return this.radio.isEnabled;
    }

    /**
     * 设置是否为选中状态
     */
    public set isChecked(isChecked: boolean) {
        if (!this.isEnabled) return;
        this._isChecked = isChecked;
        this.radio.isChecked = this._isChecked;
    }

    /**
     * 获取是否为选中状态
     */
    public get isChecked(): boolean {
        return this._isChecked;
    }

    /**
     * 添加选中状态改变时的回调函数对象
     * @param func 回调函数
     * @returns 回调函数对象
     */
    public onChange(func: { (isChecked: boolean): void }): IHandle<boolean> {
        return CreateHandleTo(func, this._changeHandles);
    }

    /**
     * 移除选中状态改变时的回调函数对象
     * @param handle 回调函数对象或其id
     */
    public removeChangeHandle(handle: number | IHandle<boolean>): void {
        RemoveHandle(handle, this._changeHandles);
    }

    protected initializeControl(name: string, scene: Scene, options: IUIRadioOptions): Control {
        const panel = new StackPanel(name + '-panel');
        panel.isVertical = options.isVertical || false;
        if (options.debug) panel.background = '#ff00ff';

        this._radioBackgroundColor = options.radioBackground || '#000000';
        this._radioColor = options.radioColor || '#ffffff';
        this._fontColor = options.fontColor || '#000000';
        this._revocable = options.revocable || false;

        const fontSize = options.fontSize || 26;
        const radioSize = options.radioSize || fontSize;
        const radio = new RadioButton(name + '-radio');
        radio.width = radioSize + 'px';
        radio.height = radioSize + 'px';
        radio.background = this._radioBackgroundColor;
        radio.color = this._radioColor;
        radio.checkSizeRatio = options.checkSizeRatio || 0.6;
        radio.group = options.group || '';
        radio.paddingLeft = '0px';
        radio.thickness = 1e-6;
        radio.isReadOnly = this._revocable;
        radio.isPointerBlocker = !this._revocable;
        this.radio = radio;
        panel.addControl(radio);

        const header = new TextBlock(name + '-header');
        header.text = options.title || 'radio';
        header.fontSize = fontSize + 'px';
        header.color = this._fontColor;
        header.fontFamily = options.fontFamily || 'Arial';
        header.width = fontSize + 'px';
        header.height = fontSize + 'px';
        header.clipContent = false;
        header.fontWeight = options.fontWeight || 'normal';
        this.header = header;
        panel.addControl(header);

        const space = options.spacing || 5;
        UIRadio.autoLayout(panel, header, space, [header], [radio]);

        return panel;
    }

    protected bindEvent(control: Control, options: IUIRadioOptions): void {
        this.radio.onIsCheckedChangedObservable.add((isChecked: boolean) => {
            if (!this.isEnabled) return;
            this._isChecked = isChecked;
            if (!this.avoidEventHandle) this._changeHandles.forEach(handle => handle.callback(isChecked));
        });
        (control as StackPanel).onPointerClickObservable.add(() => {
            if (!this.isEnabled) return;
            if (this._revocable) {
                this.radio.isChecked = !this.radio.isChecked;
            } else {
                this.radio.isChecked = true;
            }
        });
    }

    protected unbindEvent(control: Control): void {
        super.unbindEvent(control);
        this.radio.onIsCheckedChangedObservable.clear();
        (control as StackPanel).onPointerClickObservable.clear();
    }

}


/**
 * 创建单选按钮控件
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 * @param changeCallback 选中状态改变时的回调函数
 * @returns 单选按钮控件
 */
const CreateUIRadio = (name: string, scene: Scene, options?: IUIRadioOptions, changeCallback?: { (isChecked: boolean): void }): UIRadio => {
    const radio = new UIRadio(name, scene, options);
    if (changeCallback) radio.onChange(changeCallback);
    return radio;
}


export { UIRadio, CreateUIRadio };
export type { IUIRadioOptions };